import numpy as np
import tensorflow.compat.v1 as tf

# 在tensorflow下，训练一个softmax分类器，实现数据集的多分类功能
# （一）准备训练数据集x_data、y_data(8分)
# 其中x_data是[[9, 2, 1, 1],[2, 1, 3, 2],[3, 1, 3, 4],[4, 1, 5, 5],[1, 7, 5, 5],[7, 2, 5, 6],[1, 6, 6, 6],[1, 7, 7, 7]]
# y_data是[[0, 0, 1],[0, 0, 1],[0, 0, 1],[0, 1, 0],[0, 1, 0],[0, 1, 0],[1, 0, 0],[1, 0, 0]]
x_data = [[9, 2, 1, 1],[2, 1, 3, 2],[3, 1, 3, 4],[4, 1, 5, 5],[1, 7, 5, 5],[7, 2, 5, 6],[1, 6, 6, 6],[1, 7, 7, 7]]
y_data = [[0, 0, 1],[0, 0, 1],[0, 0, 1],[0, 1, 0],[0, 1, 0],[0, 1, 0],[1, 0, 0],[1, 0, 0]]
x_data = np.array(x_data)
y_data = np.array(y_data)
n = x_data.shape[1]
n_cls = y_data.shape[1]
n_hidden = 2 * n

# （二）定义张量X和Y，float32类型，使用占位符函数（8分）
x = tf.placeholder(tf.float32, [None, n], name='placeholder_x')
y = tf.placeholder(tf.float32, [None, n_cls], name='placeholder_y')

# （三）定义张量W（weight）和b（bias）（8分）
w1 = tf.Variable(tf.random.normal([n, n_hidden]), dtype=tf.float32, name='w1')
b1 = tf.Variable(tf.random.normal([1, n_hidden]), dtype=tf.float32, name='b1')
w2 = tf.Variable(tf.random.normal([n_hidden, n_cls]), dtype=tf.float32, name='w2')
b2 = tf.Variable(tf.random.normal([1, n_cls]), dtype=tf.float32, name='b2')

# （四）设置hypothesis预测模型（8分）
z1 = tf.matmul(x, w1) + b1
a1 = tf.sigmoid(z1)
z2 = tf.matmul(a1, w2) + b2
h = tf.nn.softmax(z2)
predict = tf.argmax(tf.cast(h > 0.5, dtype=tf.float32), axis=1)

# （五）设置代价函数（损失函数）（8分）
cost = tf.reduce_mean(- tf.reduce_sum(y * tf.math.log(h), axis=1))  # ATTENTION Not sum, but reduce_sum

# （六）使用梯度下降优化器计算最小费用，查找最优解（8分）
alpha = 0.1
train = tf.train.GradientDescentOptimizer(learning_rate=alpha).minimize(cost)

# accuracy
acc = tf.reduce_mean(tf.cast(tf.equal(h > 0.5, y > 0.5), dtype=tf.float32))

# （七）创建会话（Session）（8分）
with tf.Session() as sess:

    # （八）全局变量初始化（8分）
    sess.run(tf.global_variables_initializer())

    # （九）开始迭代总共3001次（6分）
    iters = 3001

    # （十）使用训练集的数据进行训练（8分）
    for i in range(iters):
        _, costv, accv = sess.run([train, cost, acc], feed_dict={x: x_data, y: y_data})

        # （十一）每100次输出cost值（6分）
        if i % 100 == 0:
            print(f'#{i + 1}, cost = {costv}, acc= {accv}')
    # finally print it
    if i % 100 != 0:
        print(f'#{i + 1}, cost = {costv}, acc= {accv}')

    # （十二）使用1个测试样本[10, 12, 11, 11]进行分类测试，输出分类结果（8分）
    print('使用1个测试样本[10, 12, 11, 11]进行分类测试，输出分类结果')
    print(sess.run(predict, feed_dict={x: [
        [10, 12, 11, 11]
    ]}))

    # （十三）使用2个测试样本[5, 1, 1, 1]、[6, 2, 2, 2]进行分类测试，输出分类结果（8分）
    print('使用2个测试样本[5, 1, 1, 1]、[6, 2, 2, 2]进行分类测试，输出分类结果')
    print(sess.run(predict, feed_dict={x: [
        [5, 1, 1, 1],
        [6, 2, 2, 2]
    ]}))
